package com.galaxy.device.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.galaxy.common.core.exception.ServiceException;
import com.galaxy.common.core.utils.MapstructUtils;
import com.galaxy.common.core.utils.StringUtils;
import com.galaxy.common.mybatis.core.page.PageQuery;
import com.galaxy.common.mybatis.core.page.TableDataInfo;
import com.galaxy.device.domain.DeviceBase;
import com.galaxy.device.domain.DeviceLocation;
import com.galaxy.device.domain.bo.DeviceLocationBo;
import com.galaxy.device.domain.convert.DeviceLocationConvert;
import com.galaxy.device.domain.vo.DeviceBaseVo;
import com.galaxy.device.domain.vo.DeviceLocationVo;
import com.galaxy.device.mapper.DeviceBaseMapper;
import com.galaxy.device.mapper.DeviceLocationMapper;
import com.galaxy.device.service.IDeviceEsService;
import com.galaxy.device.service.IDeviceLocationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 设备位置服务实现类
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class DeviceLocationServiceImpl extends ServiceImpl<DeviceLocationMapper, DeviceLocation> implements IDeviceLocationService {

    private final DeviceLocationMapper deviceLocationMapper;
    private final IDeviceEsService deviceEsService;
    private final DeviceBaseMapper baseMapper;
    private final InfluxDBServiceImpl influxDBService;

    @DS("slave")
    @Override
    public List<DeviceLocationVo> queryList(DeviceLocationBo bo) {
        LambdaQueryWrapper<DeviceLocation> lqw = new LambdaQueryWrapper<>();
        lqw.eq(bo.getDeviceId() != null, DeviceLocation::getDeviceId, bo.getDeviceId());
        lqw.like(StringUtils.isNotBlank(bo.getLocation()), DeviceLocation::getLocation, bo.getLocation());
        lqw.like(StringUtils.isNotBlank(bo.getAddress()), DeviceLocation::getAddress, bo.getAddress());
        List<DeviceLocation> list = deviceLocationMapper.selectList(lqw);
        return DeviceLocationConvert.INSTANCE.convertVoList(list);
    }

    @DS("slave")
    @Override
    public DeviceLocationVo getInfo(Long id) {
        DeviceLocation location = deviceLocationMapper.selectVoById(id);
        if (location == null) {
            throw new ServiceException("设备位置信息不存在");
        }
        return MapstructUtils.convert(location,  DeviceLocationVo.class);
    }

    @Override
    public DeviceLocationVo getLocationInfo(Long id) {
        DeviceLocation deviceLocation = deviceLocationMapper.selectVoByDeviceId(id);
        if (deviceLocation == null) {
            throw new ServiceException("设备位置信息不存在");
        }
        return MapstructUtils.convert(deviceLocation,  DeviceLocationVo.class);
    }

    @Override
    public DeviceLocation getInfoById(Long id) {
        DeviceLocation location = deviceLocationMapper.selectById(id);
        if (location == null) {
            throw new ServiceException("设备位置信息不存在");
        }
        return location;
    }

    @DS("slave")
    @Override
    public TableDataInfo<DeviceLocationVo> queryPageList(DeviceLocationBo bo, PageQuery pageQuery) {
        DeviceLocation query = new DeviceLocation();
        query.setDeviceId(bo.getDeviceId());
        query.setLocation(bo.getLocation());
        query.setAddress(bo.getAddress());
        IPage<DeviceLocationVo> page = deviceLocationMapper.selectVoPage(pageQuery.build(), query);
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DeviceLocation add(DeviceLocationBo bo) {
        try {
            // 1. 保存到数据库
            DeviceLocation location = DeviceLocationConvert.INSTANCE.convert(bo);
            deviceLocationMapper.insert(location);

//            baseMapper.update(new LambdaUpdateWrapper<DeviceBase>().eq(DeviceBase::getId, bo.getDeviceId()).eq(DeviceBase::getStatus, 0).set(DeviceBase::getStatus, 1));
            // 2. 同步到ES
            if(bo.getStatus() == 4){
                DeviceLocationVo vo = DeviceLocationConvert.INSTANCE.convertVo(location);
                if (vo.isValid()) {
                    DeviceBaseVo deviceBase = baseMapper.selectVoById(location.getDeviceId());
                    vo.setDevice(deviceBase);
                    boolean success = deviceEsService.saveOrUpdateDeviceLocation(vo);
                    if (!success) {
                        log.warn("设备位置同步到ES失败: {}", vo);
                    }
                } else {
                    log.warn("设备位置信息无效，无法同步到ES: {}", vo);
                }
            }
            return location;
        } catch (Exception e) {
            log.error("添加设备位置失败: {}", e.getMessage());
            throw new ServiceException("添加设备位置失败");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DeviceLocation update(DeviceLocationBo bo) {
        try {
            // 1. 查询原数据（使用缓存）
            DeviceLocation location = deviceLocationMapper.selectById(bo.getId());
            if (location == null) {
                throw new ServiceException("设备位置信息不存在");
            }

            // 2. 更新设备状态（批量更新）
            baseMapper.update(new LambdaUpdateWrapper<DeviceBase>()
                .eq(DeviceBase::getId, location.getDeviceId())
                .eq(DeviceBase::getStatus, 0)
                .set(DeviceBase::getStatus, 1)
                .set(DeviceBase::getUpdateTime, LocalDateTime.now()));

            // 3. 更新数据库（批量更新）
            MapstructUtils.convert(bo, location);
            // 将 LocalDateTime 转换为 Date
            Date updateTime = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
            location.setUpdateTime(updateTime);
            deviceLocationMapper.updateById(location);

            if(bo.getStatus() == 4) {
                baseMapper.update(new LambdaUpdateWrapper<DeviceBase>().eq(DeviceBase::getId, bo.getDeviceId()).eq(DeviceBase::getStatus, 0).set(DeviceBase::getStatus, 1));
                // 4. 同步到ES（异步处理）
                CompletableFuture.runAsync(() -> {
                    try {
                        DeviceLocationVo vo = DeviceLocationConvert.INSTANCE.convertVo(location);
                        if (vo.isValid()) {
                            DeviceBaseVo deviceBase = baseMapper.selectVoById(location.getDeviceId());
                            vo.setDevice(deviceBase);
                            boolean success = deviceEsService.saveOrUpdateDeviceLocation(vo);
                            if (!success) {
                                log.warn("设备位置同步到ES失败: {}", vo);
                            }
                        } else {
                            log.warn("设备位置信息无效，无法同步到ES: {}", vo);
                        }
                    } catch (Exception e) {
                        log.error("异步同步到ES失败: {}", e.getMessage());
                    }
                });
            }
            return location;
        } catch (Exception e) {
            log.error("更新设备位置失败: {}", e.getMessage());
            throw new ServiceException("更新设备位置失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        try {
            // 1. 查询原数据
            DeviceLocation location = deviceLocationMapper.selectById(id);
            if (location == null) {
                return;
            }
            baseMapper.update(new LambdaUpdateWrapper<DeviceBase>().eq(DeviceBase::getId, id).set(DeviceBase::getStatus, 0));
            // 2. 删除数据库数据
            deviceLocationMapper.deleteById(id);

            // 3. 从ES中删除
            boolean success = deviceEsService.deleteDevice(String.valueOf(location.getDeviceId()));
            if (!success) {
                log.warn("从ES删除设备位置失败: {}", location.getDeviceId());
            }
        } catch (Exception e) {
            log.error("删除设备位置失败: {}", e.getMessage());
            throw new ServiceException("删除设备位置失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        try {
            if (ids == null || ids.length == 0) {
                return;
            }

            // 1. 批量查询原数据
            List<DeviceLocation> locations = deviceLocationMapper.selectBatchIds(Arrays.asList(ids));
            if (CollUtil.isEmpty(locations)) {
                return;
            }

            // 2. 批量更新设备状态
            List<Long> deviceIds = locations.stream()
                .map(DeviceLocation::getDeviceId)
                .collect(Collectors.toList());
            baseMapper.update(new LambdaUpdateWrapper<DeviceBase>()
                .in(DeviceBase::getId, deviceIds)
                .set(DeviceBase::getStatus, 0)
                .set(DeviceBase::getUpdateTime, LocalDateTime.now()));

            // 3. 批量删除数据库数据
            deviceLocationMapper.deleteBatchIds(Arrays.asList(ids));

            // 4. 异步从ES中删除
            CompletableFuture.runAsync(() -> {
                try {
                    for (DeviceLocation location : locations) {
                        boolean success = deviceEsService.deleteDevice(String.valueOf(location.getDeviceId()));
                        if (!success) {
                            log.warn("从ES删除设备位置失败: {}", location.getDeviceId());
                        }
                    }
                } catch (Exception e) {
                    log.error("异步从ES删除失败: {}", e.getMessage());
                }
            });
        } catch (Exception e) {
            log.error("批量删除设备位置失败: {}", e.getMessage());
            throw new ServiceException("批量删除设备位置失败");
        }
    }
}
